/*
 * texturegrammar.cpp
 *
 *  Created on: 15/11/2012
 *      Author: cvan680
 */


#include "texturegrammar.h"

#include <fstream>
#include <streambuf>

#include <stdio.h>
#include <string.h>

#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

namespace voreen {

TextureGrammar::TextureGrammar(string filename){

	filename_ = filename;
	filecontents_ = readFile(filename_);
	contents_ = tokenize(filecontents_, "\n");
	contents_ = clearComments(contents_);
	rules_ = makeRules(contents_);

	std::cout << "\n\ndone MAKING RULES: " << rules_.size() << "\n---------------------------\n";

	currentState_ = NodeList("S");

	hasrun_ = false;
}



void TextureGrammar::run(){

	std::cout << "\nrunning Texture Grammar\n------------------------------------";

	Rule* r;

	bool a_rule_has_fired = true;
	while(a_rule_has_fired){
		std::cout << "\nstate: ";
		currentState_.printMe();

		a_rule_has_fired = false;
		for(int i=0, k=rules_.size(); i<k; ++i){
			r = rules_.at(i);
			if(r->fires(currentState_)){
				std::cout << "\nfiring rule";
				r->printString();
				currentState_.replaceFirstOccurrence(r->getPredecessor(), r->getSuccessor());
				a_rule_has_fired = true;
				break;
			}
		}
	}

	std::cout << "\n\nfinished! Final state:\n---------------------------------------";
	currentState_.printMe();

	hasrun_ = true;
}

// only call these two methods after running the grammar
int TextureGrammar::getNumberOfNodes(){ return currentState_.length(); }
int TextureGrammar::getNumberOfFields(){ return (currentState_.length()+1)/2; }
TechniqueWrapper TextureGrammar::getNode(int index){ return currentState_.get(index).getTechnique(); }


bool TextureGrammar::completed(){
	return hasrun_;
}

void TextureGrammar::setForReRun(){
	hasrun_ = false;
}



string TextureGrammar::readFile(string fname){
// taken from http://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring

	std::ifstream t(fname);
	std::stringstream buffer;
	buffer << t.rdbuf();

	return buffer.str();
}

void TextureGrammar::printState(){ std::cout << "\nstate: ["; currentState_.printMe(); std::cout << "]"; }
void TextureGrammar::printFileContents(){ std::cout << "\nfile contents:\n---------------------\n" << filecontents_; }

std::vector<string> TextureGrammar::tokenize(string contents, string delimiter){
	std::vector<string> temps;
	string tmp;

	while(contents.length() > 0){
		int i = contents.find( delimiter );

		if(i >= 0 && i < contents.length()){
			tmp = contents.substr(0, i);
			tmp = trimmer(tmp);
			temps.push_back(tmp);
			contents.erase(0, i+delimiter.size()); // also remove delimiter
		}else{
			contents = trimmer(contents);
			temps.push_back(contents);
			contents = "";
		}
	}

	return temps;
}

std::vector<string> TextureGrammar::clearComments(std::vector<string> lines){
	std::vector<string> res;

	string tmp;
	for(int i=0; i<lines.size(); ++i){
		tmp = lines.at(i);
		int index = tmp.find("#");

		if(index != 0){
			tmp = tmp.substr(0, index);
			if(tmp.size() > 1){ // dont keep any 1-long strings
				tmp = trimmer(tmp);
				res.push_back(tmp);
			}
		}
	}

	return res;
}

std::vector<Rule*> TextureGrammar::makeRules(std::vector<string> lines){
	std::vector<Rule*> rules;
	Rule* trule;
	for(int i=0, k=lines.size(); i<k; ++i){
		trule = new Rule(lines.at(i));
		rules.push_back(trule);
	}
	return rules;
}


string TextureGrammar::trimmer(string s){
	// trim trailing spaces
	size_t endpos = s.find_last_not_of(" \t");
	if( string::npos != endpos ){ s = s.substr( 0, endpos+1 ); }
	size_t startpos = s.find_first_not_of(" \t");
	if( string::npos != startpos ){ s = s.substr( startpos ); }
	return s;
}




}

